﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;


namespace TCP
{
    class Server
    {
        private TcpListener tcpListener;
        private Thread serverThread;

        private Dictionary<IPEndPoint, TcpClient> clients;

        public delegate void clientConnectedEventHandler(TcpClient client);
        public event clientConnectedEventHandler clientConnectedEvent;

        public delegate void clientDisconnectedEventHandler(TcpClient client, string raison);
        public event clientDisconnectedEventHandler clientDisconnectedEvent;

        public delegate void clientDataEventHandler(TcpClient client, byte[] data);
        public event clientDataEventHandler clientDataReceivedEvent;
        public event clientDataEventHandler clientDataSendedEvent;
 
        public Server(int port)
        {
            this.clients = new Dictionary<IPEndPoint, TcpClient>();
            this.tcpListener = new TcpListener(IPAddress.Any, port);
            this.serverThread = new Thread(WaitForClientLoop);
            this.serverThread.Start();
        }

        private void WaitForClientLoop()
        {
            this.tcpListener.Start();

            while (true)
            {
                TcpClient client = this.tcpListener.AcceptTcpClient();
                clients.Add((System.Net.IPEndPoint)client.Client.RemoteEndPoint, client);

                Thread clienThread = new Thread(new ParameterizedThreadStart(ReceptionLoop));                                          
                clienThread.Start(client);                
            }
        }

        private void ReceptionLoop(object tcpclient)
        {
            TcpClient client = (TcpClient)tcpclient;
            NetworkStream clientStream = client.GetStream(); 

            byte[] ReceiveBuffer = new byte[client.ReceiveBufferSize];            
            int bytesRead;

            if (clientConnectedEvent != null) clientConnectedEvent(client);

            while (true)
            {
                bytesRead = 0;
                try
                {
                    clientStream.Flush();
                    bytesRead = clientStream.Read(ReceiveBuffer, 0, client.ReceiveBufferSize);
                }
                catch (System.IO.IOException ex)
                {
                    if (clientDisconnectedEvent != null) clientDisconnectedEvent(client,"socket failure");
                    break;
                }

                if (bytesRead == 0)
                {
                    if (clientDisconnectedEvent != null) clientDisconnectedEvent(client,"quit");
                    break;
                }

                byte[] data = new byte[bytesRead];
                Array.Copy(ReceiveBuffer, data, bytesRead);

                if (clientDataReceivedEvent != null) clientDataReceivedEvent(client, data);                
            }

            client.Close();
        }

        public void SendTo(TcpClient client, byte[] data)
        {
            NetworkStream clientStream = client.GetStream();
            clientStream.Write(data, 0, data.Length);
            if (clientDataSendedEvent != null) clientDataSendedEvent(client, data);
        }
    }
}
